﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using QuickFix;
using PSE.Communication.Fix.Common;
using System.Configuration;
using System.Reflection;
using System.IO;

namespace PSE.Communication.Fix.Server.Session
{
    public class SessionManager
    {
        private static Mutex _mutex = new Mutex();
        private static SessionManager _sessionManager = null;
        private Dictionary<string, Session> _sessions = null;
        private Thread _threadVerifySessions;
        private ManualResetEvent _exitVerifySessions;
        private int _laps;

        public static SessionManager GetInstance()
        {
            try
            {
                _mutex.WaitOne();

                if (_sessionManager == null)
                {
                    _sessionManager = new SessionManager();
                }
            }
            finally
            {
                _mutex.ReleaseMutex();
            }

            return _sessionManager;
        }

        public SessionManager()
        {
            _exitVerifySessions = new ManualResetEvent(false);
            _threadVerifySessions = new Thread(new ThreadStart(VerifySessions));
            _sessions = new Dictionary<string, Session>();
        }

        public void Start()
        {
            ConfigurationManager.RefreshSection("fixConfiguration");

            FixConfigurationSection fixConfiguration = (FixConfigurationSection)ConfigurationManager.GetSection("fixConfiguration");

            if (fixConfiguration != null)
            {
                for (int i = 0; i < _sessions.Count - 1; i++)
                {
                    if (_sessions.ElementAt(i).Value.State != CommunicationState.Opened)
                    {
                        _sessions.Remove(_sessions.ElementAt(i).Key);
                    }
                }

                foreach (FixSessionConfigurationElement item in fixConfiguration.FixSessions)
                {
                    try
                    {
                        if (!_sessions.ContainsKey(item.Name))
                        {
                            Session session = new Session(item, fixConfiguration.DataDictionary);
                            _sessions.Add(item.Name, session);
                        }
                    }
                    catch (Exception ex)
                    {
                        if (_sessions.ContainsKey(item.Name))
                            _sessions.Remove(item.Name);

                        Logger.Write(new Exception(string.Format("Cannot initialize fix session with name '{0}'", item.Name), ex));
                    }
                }

                if (_threadVerifySessions.ThreadState == ThreadState.Unstarted)
                    _threadVerifySessions.Start();
            }
            else
                throw new Exception("Section fixConfiguration not found in the config file");
        }

        public void Stop()
        {
            _exitVerifySessions.Set();

            foreach (KeyValuePair<string, Session> item in _sessions)
                item.Value.Dispose();
        }

        private void VerifySessions()
        {
            while (!_exitVerifySessions.WaitOne(0))
            {
                _laps++;

                if (_laps == 100)
                {
                    Thread.Sleep(1);
                    _laps = 0;
                }

                Thread.Sleep(10000);

                try
                {
                    this.Start();
                }
                catch (Exception ex)
                {
                    Logger.Write(ex);
                }                
            }
        }
    }
}
